package com.easy.dev.utils;

import lombok.extern.slf4j.Slf4j;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Slf4j
public class DateUtils {
    private static final ConcurrentMap<String, DateTimeFormatter> FORMATTER_CACHE = new ConcurrentHashMap<>();

    private static final int PATTERN_CACHE_SIZE = 500;

    private static Integer nowDate ;

    /**
     * 得到日期int数据
     * 格式为20191127
     * @return
     */
    public static Integer getDateInt(Date date){
        String d = format(date,"yyyyMMdd");
        return Integer.valueOf(d);
    }

    public static int compare(Integer time) {
        Integer now = getNowDateInt();
        return time - now;
    }

    public static Integer getYestodayInt(){
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, -1);
        Date date = c.getTime();
        String d = format(date,"yyyyMMdd");
        return Integer.valueOf(d);
    }

    public static Integer getTodayBeforeInt(Integer year, Integer month, Integer day){
        Calendar c = Calendar.getInstance();
        if (year != null) {
            c.add(Calendar.YEAR, -year);
        }
        if (month != null) {
            c.add(Calendar.MONTH, -month);
        }
        if (day != null) {
            c.add(Calendar.DATE, -day);
        }
        Date date = c.getTime();
        String d = format(date,"yyyyMMdd");
        return Integer.valueOf(d);
    }

    public static Integer getMaxDateByYearAndMonth(int year, int month) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month-1, 1);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    public static Long getYestodayLastLongTime(Integer date) {
        try{
            Date d = new SimpleDateFormat("YYYYMMDD").parse(String.valueOf(date));
            return d.getTime() -1;
        }catch(Exception e) {

        }
        return 0l;
    }

    public static Integer getBeforeYestodayInt(){
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, -2);
        Date date = c.getTime();
        String d = format(date,"yyyyMMdd");
        return Integer.valueOf(d);
    }

    public static Integer getNowDateInt(){
        if (nowDate == null) {
            nowDate = getDateInt(new Date());
        }
        return nowDate;
    }

    /**
     * 得到当前时间时分秒
     * @return
     */
    public static Integer getNowTime() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, -1);
        Date date = c.getTime();
        String d = format(date,"HHmmss");
        return Integer.valueOf(d);
    }


    //TODO 需加锁
    public static void setNowDate(){
        nowDate = null;
    }

    /**
     * 根据日期得到13位时间戳
     * @param date   2019-11-28
     * @return
     */
    public static Long getTimeByDate(String date){
        LocalDate d = LocalDate.parse(date);
        return d.atStartOfDay(ZoneOffset.ofHours(8)).toInstant().toEpochMilli();
    }

    /**
     * Date转换为格式化时间
     * @param date date
     * @param pattern 格式
     * @return
     */
    public static String format(Date date, String pattern){
        return format(LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()), pattern);
    }

    /**
     * localDateTime转换为格式化时间
     * @param localDateTime localDateTime
     * @param pattern 格式
     * @return
     */
    public static String format(LocalDateTime localDateTime, String pattern){
        DateTimeFormatter formatter = createCacheFormatter(pattern);
        return localDateTime.format(formatter);
    }

    /**
     * 格式化字符串转为Date
     * @param time 格式化时间
     * @param pattern 格式
     * @return
     */
    public static Date parseDate(String time, String pattern){
        return Date.from(parseLocalDateTime(time, pattern).atZone(ZoneId.systemDefault()).toInstant());

    }

    /**
     * 格式化字符串转为LocalDateTime
     * @param time 格式化时间
     * @param pattern 格式
     * @return
     */
    public static LocalDateTime parseLocalDateTime(String time, String pattern){
        DateTimeFormatter formatter = createCacheFormatter(pattern);
        return LocalDateTime.parse(time, formatter);
    }

    /**
     * 在缓存中创建DateTimeFormatter
     * @param pattern 格式
     * @return
     */
    private static DateTimeFormatter createCacheFormatter(String pattern){
        if (pattern == null || pattern.length() == 0) {
            throw new IllegalArgumentException("Invalid pattern specification");
        }
        DateTimeFormatter formatter = FORMATTER_CACHE.get(pattern);
        if(formatter == null){
            if(FORMATTER_CACHE.size() < PATTERN_CACHE_SIZE){
                formatter = DateTimeFormatter.ofPattern(pattern);
                DateTimeFormatter oldFormatter = FORMATTER_CACHE.putIfAbsent(pattern, formatter);
                if(oldFormatter != null){
                    formatter = oldFormatter;
                }
            }
        }

        return formatter;
    }


    /**
     * 格式化日期
     * @param str
     * @param format
     * @return
     * @throws ParseException
     */
    public static Date StringToDate(String str, String format) throws ParseException {
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        Date date = (Date) formatter.parse(str);
        return date;
    }


    /**
     * Date 类型转化为 Long 类型(精确到毫秒)
     * @param date
     * @return
     */
    public static Long dateToLong(Date date){
        return date.getTime();
    }


    /**
     * date类型进行格式化输出（返回类型：String）
     * @param date
     * @return
     */
    public static String dateFormat(Date date, String format) {
        if(format == null || "".equals(format)) {
            format = "yyyy-MM-dd HH:mm:ss";
        }
        SimpleDateFormat formatter = new SimpleDateFormat(format);
        String dateString = formatter.format(date);
        return dateString;
    }


    // 根据年月得到当月天数
    public static int getDaysByYearMonth(int year, int month)
    {
        Calendar a = Calendar.getInstance();
        a.set(Calendar.YEAR, year);
        a.set(Calendar.MONTH, month - 1);
        a.set(Calendar.DATE, 1);
        a.roll(Calendar.DATE, -1);
        int maxDate = a.get(Calendar.DATE);
        return maxDate;
    }

    /**
     * 获取当天开始时间
     * @return
     */
    public static Date getDayBegin(){
        Calendar cal= Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 0);//0点
        cal.set(Calendar.MINUTE, 0);//0分
        cal.set(Calendar.SECOND, 0);//0秒
        cal.set(Calendar.MILLISECOND, 0);//0毫秒
        return cal.getTime();
    }


    /**
     * 获取当天结束时间
     * @return
     */
    public static Date getDayEnd(){
        Calendar cal= Calendar.getInstance();
        cal.set(Calendar.HOUR_OF_DAY, 23);//23点
        cal.set(Calendar.MINUTE, 59);//59分
        cal.set(Calendar.SECOND, 59);//59秒
        return cal.getTime();
    }



    /**
     * 获取昨天开始时间
     * @return
     */
    public static Date getBeginDayOfYesterday(){
        Calendar cal= Calendar.getInstance();
        cal.setTime(getDayBegin());//当天开始时间
        cal.add(Calendar.DAY_OF_MONTH, -1);//当天月份天数减1
        return cal.getTime();
    }


    /**
     * 获取昨天结束时间
     * @return
     */
    public static Date getEndDayOfYesterday(){
        Calendar cal= Calendar.getInstance();
        cal.setTime(getDayEnd());//当天结束时间
        cal.add(Calendar.DAY_OF_MONTH, -1);//当天月份天数减1
        return cal.getTime();
    }


    /**
     * 获取今天开始时间
     * @return
     */
    public static Date getBeginDayOfToday(){
        Calendar cal= Calendar.getInstance();
        cal.setTime(getDayBegin());//当天开始时间
        cal.add(Calendar.DAY_OF_MONTH, 0);
        return cal.getTime();
    }


    /**
     * 获取今天结束时间
     * @return
     */
    public static Date getEndDayOfToday(){
        Calendar cal= Calendar.getInstance();
        cal.setTime(getDayEnd());//当天结束时间
        cal.add(Calendar.DAY_OF_MONTH, 0);
        return cal.getTime();
    }

    public static void main(String[] args) {
        // System.out.println(getCronExpressionByTimeZoneAndTime("GMT-8:00","16:01 AM"));
    }
}
